from django.utils import timezone
from random import choices
from django.db.models.signals import post_save
from django.dispatch import receiver
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
from django.db import models
from django.core.cache import cache
from django.contrib.auth.models import AbstractUser
from django.contrib.gis.db import models as gis_models
import redis
from django.db import transaction
"""
post_save信号会在UserProfile保存后触发

get_dirty_fields()检查哪些字段被修改

async_to_sync将异步调用转换为同步

group_send向指定频道组发送消息
"""
class UserProfile(AbstractUser):
    genderoptions = (
        (1, '男'),
        (0, '女'),
    )
    telephone = models.CharField(max_length=11)
    icon = models.ImageField(upload_to='icon', default='icon/default.jpg')
    password = models.CharField(max_length=100, null=True,blank=True,verbose_name='密码')
    nickname = models.CharField(max_length=20, null=True, blank=True,verbose_name='昵称')
    birthday = models.DateField(null=True, blank=True,verbose_name='生日')
    city = models.CharField(max_length=20, null=True, blank=True,verbose_name='城市')
    occupation= models.CharField(max_length=11, null=True, blank=True,verbose_name='职业')
    gender = models.SmallIntegerField(choices=genderoptions, default=1,verbose_name='性别')
    like_people = models.ManyToManyField('self', related_name='liked_user_list',blank=True,verbose_name='喜欢的人', through="relationship",through_fields=('myid', 'liked_user_id'))
    personalized_signature=models.CharField(max_length=100, null=True, blank=True,verbose_name='个性签名')
    location = gis_models.PointField(null=True, blank=True,verbose_name='位置')
    location_updated = models.DateTimeField(auto_now=True)  # 新增更新时间字段
        # ... 其他字段 ...
class relationship(models.Model):
    """
        好友关系表，用于存储用户之间的关系
    """
    myid=models.ForeignKey(UserProfile,on_delete=models.CASCADE,related_name='myid',verbose_name='我的id',null=True,blank=True)
    liked_user_id=models.ForeignKey(UserProfile,on_delete=models.CASCADE,related_name='liked_user',verbose_name='好友id',null=True,blank=True)
    created_at=models.DateTimeField(auto_now_add=True,verbose_name='创建时间',null=True,blank=True)
    is_like=models.BooleanField(verbose_name='是否喜欢',default=False,null=True,blank=True)
    def save(self, *args, **kwargs):
        from friend.models import Friendship
        """
            重写保存方法实现通知机制，当双方互相喜欢发送通知
        """
        with transaction.atomic():
            if self.is_like:
                print("触发器触发并且喜欢了某个用户")
                print(self.myid.id)
                print(self.liked_user_id.id)
                # 筛选查看有没有其他用户喜欢了我,
                relationship_obj=relationship.objects.filter(myid=self.liked_user_id,liked_user_id=self.myid,is_like=True).first()
                if relationship_obj:
                    print("双方相互喜欢了")
                    # 发送通知
                    self.notify_like_each_other()
                    Friendship.objects.create(user1=self.myid,user2=self.liked_user_id)
            super().save(*args, **kwargs)  # 调用父类保存方法
    def notify_like_each_other(self):
        """
            通过channels发送实时通知
            1. 获取channel_layer对象（连接redis）
            2. 使用async_to_sync将异步调用转换为同步
            3. 向特定用户组的websocket连接发送消息
             组名格式：balance_{user_id}
             事件类型对应consumer的blance_update方法
        """
        from socket_chat.models import notificationMessage
        from . import serializers
        content_text='恭喜您！，配对成功啦！%s也喜欢了您，快去看看吧'
        print('触发通知')
        r = redis.Redis(host='localhost', port=6379, db=0)
        channel_layer = get_channel_layer() #获取通道层实例
        my_private_group=cache.get(f'private_{self.myid}')
        print("my_my_private_group",my_private_group)
        try:
            group_key = f"asgi:group:private_{self.myid.id}"
            # 获取有序集合成员数量
            member_count = r.zcard(group_key)
            is_received = member_count > 0
            print(f'用户在线状态: {is_received}（成员数：{member_count}）')
            # 在同步代码中必须使用async_to_sync来调用异步方法
            # async_to_sync的主要作用是将异步（async）方法包装为同步方法调用
            # group_send只是将详细消息发送到频道组，而不是直接发送给客户端。在频道组中，每个连接到WebSocket的消费者都有一个频道名，
            async_to_sync(channel_layer.group_send)(
                f"private_{self.myid.id}",  # 正确参数传递方式
                {
                    # 添加
                    "type": "notify.message",  # 必须包含type字段，该字段指定要调用的方法名，notify.message是consumer中的方法名
                    "message": {
                                "content": content_text%self.liked_user_id.nickname,
                                "receiver": self.myid,
                                "is_received": is_received,
                                "friend": self.liked_user_id,
                                "timestamp": timezone.now(),
                    }
                }
            )

        except Exception as e:
            print(f'Redis查询失败: {str(e)}')
            is_received = False
        my_notification_dict = {
            "content": content_text%self.liked_user_id.nickname,
            "receiver": self.myid,
            "is_received": is_received,
            "friend": self.liked_user_id,
            "timestamp": timezone.now(),
        }

        # 如果我在线，我就发送通知，否则不发送通知
        try:
            group_key = f"asgi:group:private_{self.liked_user_id.id}"
            # 获取有序集合成员数量
            member_count = r.zcard(group_key)
            is_received = member_count > 0
            print(f'用户在线状态: {is_received}（成员数：{member_count}）')
            async_to_sync(channel_layer.group_send)(
                f"private_{self.liked_user_id}",  # 正确参数传递方式
                {
                    "type": "notify.message",  # 必须包含type字段
                    "message": {
                        "content": content_text,
                        "friend": serializers.UserProfileSerializer(self.myid).data,
                        "timestamp": timezone.now(),
                        "is_read":False,
                    }
                }
            )
        except Exception as e:
            print("数据库错误")
            print(f'Redis查询失败: {str(e)}')
            is_received = False
            # 如果不在线，保存到数据库，等用户上线时发送通知
        #
        other_notification_dict = {
            "content": content_text%self.myid.nickname,
            "receiver": self.liked_user_id,
            "is_received": is_received,
            "friend": self.myid,
        }
        notification_list=[
            notificationMessage(**my_notification_dict),
            notificationMessage(**other_notification_dict),
        ]
        try:
            notificationMessage.objects.bulk_create(notification_list)
        except Exception as e:
            print(f'保存通知失败: {str(e)}')
            # 如果不在线，保存到数据库，等用户上线时发送通知
            # notificationMessage.objects.bulk_create(notification_list)
class userPhotos(models.Model):
    user=models.ForeignKey(UserProfile,on_delete=models.CASCADE,related_name='user',verbose_name='用户')
    photo=models.ImageField(upload_to='userPhoto',verbose_name='照片')
    created_at=models.DateTimeField(auto_now_add=True,verbose_name='创建时间')
